#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
异常处理模块高级用法示例

该示例展示了异常处理模块的高级用法，包括自定义异常层次结构、异常链、异常转换、
异常过滤、异常分析和与其他模块的集成。

创建时间: 2023-07-01
作者: Python Tools Team
"""

import json
import time
import random
from typing import Dict, Any, List, Optional, Union, Callable
from functools import wraps

# 导入异常类型
from modules.exception.exception_types import (
    BaseAppException,
    DatabaseException,
    ValidationException,
    NetworkException,
    TimeoutException,
    ResourceException,
    OperationException
)

# 导入异常处理工具
from modules.exception.exception_handler import (
    exception_handler,
    retry_on_exception,
    exception_context,
    log_exception,
    handle_exception
)

# 导入异常管理器
from modules.exception.exception_manager import (
    register_exception,
    register_global_handler,
    create_exception,
    exception_manager
)

# 导入日志管理器
from modules.logger import LogManager

# 创建日志记录器
logger = LogManager.get_both_logger(name="exception_advanced")


# 示例1: 创建异常层次结构
@register_exception
class APIException(BaseAppException):
    """API相关异常的基类"""
    default_code = 5000


@register_exception
class APIRequestException(APIException):
    """API请求异常"""
    default_code = 5100


@register_exception
class APIResponseException(APIException):
    """API响应异常"""
    default_code = 5200


@register_exception
class APIAuthenticationException(APIRequestException):
    """API认证异常"""
    default_code = 5101


@register_exception
class APIRateLimitException(APIRequestException):
    """API速率限制异常"""
    default_code = 5102


@register_exception
class APIResponseFormatException(APIResponseException):
    """API响应格式异常"""
    default_code = 5201


# 示例2: 异常链和异常转换
def fetch_api_data(url: str, auth_token: Optional[str] = None) -> Dict[str, Any]:
    """模拟从API获取数据，演示异常链和异常转换"""
    try:
        # 模拟网络请求
        if "invalid" in url:
            raise NetworkException(message=f"无法连接到 {url}", code=4040)
        
        # 模拟认证失败
        if auth_token is None or auth_token == "invalid":
            raise APIAuthenticationException(message="认证失败", code=5101)
        
        # 模拟速率限制
        if random.random() < 0.3:  # 30%的概率触发速率限制
            raise APIRateLimitException(message="API调用次数超过限制", code=5102)
        
        # 模拟响应解析
        response_data = {"status": "success", "data": {"id": 123, "name": "Test Item"}}
        return response_data
    
    except NetworkException as e:
        # 转换为API异常并保留原始异常信息
        raise APIRequestException(
            message=f"API请求失败: {e.message}",
            code=5100,
            details={"url": url},
            cause=e  # 保留原始异常作为cause
        )
    except (APIAuthenticationException, APIRateLimitException) as e:
        # 这些已经是API异常，直接重新抛出
        raise
    except Exception as e:
        # 捕获所有其他异常并转换为通用API异常
        raise APIException(
            message=f"API操作失败: {str(e)}",
            cause=e
        )


# 示例3: 异常过滤和分析
class ExceptionAnalyzer:
    """异常分析器，用于收集和分析异常信息"""
    
    def __init__(self):
        self.exceptions: List[Dict[str, Any]] = []
    
    def collect(self, exception: Exception) -> None:
        """收集异常信息"""
        if isinstance(exception, BaseAppException):
            # 对于自定义异常，收集完整信息
            self.exceptions.append(exception.to_dict())
        else:
            # 对于标准异常，收集基本信息
            self.exceptions.append({
                "type": exception.__class__.__name__,
                "message": str(exception),
                "traceback": traceback.format_exc() if traceback else None
            })
    
    def get_exception_count(self) -> int:
        """获取收集的异常数量"""
        return len(self.exceptions)
    
    def get_exception_types(self) -> Dict[str, int]:
        """获取各类型异常的数量"""
        type_counts = {}
        for exc in self.exceptions:
            exc_type = exc.get("type")
            if exc_type:
                type_counts[exc_type] = type_counts.get(exc_type, 0) + 1
        return type_counts
    
    def get_most_common_exception(self) -> Optional[str]:
        """获取最常见的异常类型"""
        type_counts = self.get_exception_types()
        if not type_counts:
            return None
        return max(type_counts.items(), key=lambda x: x[1])[0]
    
    def clear(self) -> None:
        """清除收集的异常信息"""
        self.exceptions.clear()


# 创建异常分析器实例
exception_analyzer = ExceptionAnalyzer()


# 异常收集装饰器
def collect_exceptions(func):
    """收集函数执行过程中的异常"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            # 收集异常信息
            exception_analyzer.collect(e)
            # 重新抛出异常
            raise
    return wrapper


# 示例4: 与其他模块集成 - 数据库操作
class MockDatabase:
    """模拟数据库，用于演示与异常处理模块的集成"""
    
    def __init__(self):
        self.connected = False
        self.data = {}
    
    @exception_handler(exception_type=Exception, reraise=True, reraise_as=DatabaseException)
    def connect(self) -> bool:
        """连接数据库"""
        logger.info("连接数据库...")
        # 模拟连接失败
        if random.random() < 0.2:  # 20%的概率连接失败
            raise Exception("数据库连接失败: 连接超时")
        
        self.connected = True
        return True
    
    @exception_handler(exception_type=Exception, reraise=True, reraise_as=DatabaseException)
    def disconnect(self) -> None:
        """断开数据库连接"""
        logger.info("断开数据库连接...")
        self.connected = False
    
    def _ensure_connected(self) -> None:
        """确保数据库已连接"""
        if not self.connected:
            raise DatabaseException(message="数据库未连接", code=5001)
    
    @retry_on_exception(max_attempts=3, delay=0.5, exception_type=DatabaseException)
    def query(self, table: str, query: Dict[str, Any]) -> List[Dict[str, Any]]:
        """查询数据"""
        self._ensure_connected()
        logger.info(f"查询表 {table}: {query}")
        
        # 模拟查询失败
        if random.random() < 0.3:  # 30%的概率查询失败
            raise DatabaseException(message=f"查询表 {table} 失败", code=5002)
        
        # 模拟查询结果
        results = []
        for i in range(3):
            results.append({"id": i, "name": f"Item {i}", "value": random.randint(1, 100)})
        
        return results
    
    @collect_exceptions
    def insert(self, table: str, data: Dict[str, Any]) -> int:
        """插入数据"""
        self._ensure_connected()
        logger.info(f"插入数据到表 {table}: {data}")
        
        # 模拟插入失败
        if random.random() < 0.2:  # 20%的概率插入失败
            raise DatabaseException(message=f"插入数据到表 {table} 失败", code=5003)
        
        # 模拟插入成功
        record_id = random.randint(1000, 9999)
        self.data[record_id] = data
        return record_id


# 示例5: 资源管理与异常处理
class Resource:
    """模拟资源，用于演示资源管理与异常处理"""
    
    def __init__(self, name: str):
        self.name = name
        self.acquired = False
    
    def acquire(self) -> None:
        """获取资源"""
        logger.info(f"获取资源: {self.name}")
        # 模拟资源获取失败
        if random.random() < 0.3:  # 30%的概率获取失败
            raise ResourceException(message=f"无法获取资源: {self.name}", code=6001)
        
        self.acquired = True
    
    def release(self) -> None:
        """释放资源"""
        if self.acquired:
            logger.info(f"释放资源: {self.name}")
            self.acquired = False


class ResourceManager:
    """资源管理器，用于安全地管理资源"""
    
    def __init__(self):
        self.resources: List[Resource] = []
    
    def add_resource(self, resource: Resource) -> None:
        """添加资源"""
        self.resources.append(resource)
    
    def acquire_all(self) -> None:
        """获取所有资源"""
        acquired_resources = []
        
        try:
            for resource in self.resources:
                resource.acquire()
                acquired_resources.append(resource)
        except Exception as e:
            # 发生异常时释放已获取的资源
            for resource in acquired_resources:
                try:
                    resource.release()
                except Exception as release_error:
                    log_exception(release_error, log_level="WARNING", message=f"释放资源 {resource.name} 失败")
            
            # 重新抛出原始异常
            raise
    
    def release_all(self) -> None:
        """释放所有资源"""
        for resource in self.resources:
            try:
                resource.release()
            except Exception as e:
                log_exception(e, log_level="WARNING", message=f"释放资源 {resource.name} 失败")
    
    def __enter__(self) -> 'ResourceManager':
        """上下文管理器入口"""
        self.acquire_all()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
        """上下文管理器退出"""
        self.release_all()
        return False  # 不抑制异常


# 示例6: 操作重试与回退策略
def with_backoff(max_attempts: int = 3, initial_delay: float = 1.0, backoff_factor: float = 2.0,
                exception_types: Union[Type[Exception], List[Type[Exception]]] = Exception,
                on_retry: Optional[Callable[[Exception, int, float], None]] = None):
    """带有指数回退的重试装饰器"""
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            nonlocal on_retry
            
            # 默认的重试回调函数
            if on_retry is None:
                def default_on_retry(exc, attempt, delay):
                    logger.warning(
                        f"函数 {func.__name__} 执行失败 (尝试 {attempt}/{max_attempts}): {str(exc)}. "
                        f"将在 {delay:.2f} 秒后重试."
                    )
                on_retry = default_on_retry
            
            current_delay = initial_delay
            last_exception = None
            
            for attempt in range(1, max_attempts + 1):
                try:
                    return func(*args, **kwargs)
                except exception_types as e:
                    last_exception = e
                    
                    if attempt < max_attempts:
                        # 调用重试回调函数
                        on_retry(e, attempt, current_delay)
                        
                        # 等待指定时间后重试
                        time.sleep(current_delay)
                        
                        # 增加延迟时间（指数回退）
                        current_delay *= backoff_factor
                    else:
                        logger.error(
                            f"函数 {func.__name__} 在 {max_attempts} 次尝试后仍然失败: {str(e)}",
                            exc_info=True
                        )
            
            # 所有重试都失败，重新抛出最后一个异常
            if last_exception:
                raise last_exception
            
            # 这里理论上不会执行到，但为了类型检查添加
            return None
        
        return wrapper
    
    return decorator


# 示例7: 异常处理与事务管理
class Transaction:
    """模拟事务，用于演示异常处理与事务管理"""
    
    def __init__(self, name: str):
        self.name = name
        self.started = False
        self.committed = False
        self.rolled_back = False
    
    def start(self) -> None:
        """开始事务"""
        logger.info(f"开始事务: {self.name}")
        self.started = True
    
    def commit(self) -> None:
        """提交事务"""
        if not self.started:
            raise OperationException(message="事务尚未开始，无法提交", code=7001)
        
        logger.info(f"提交事务: {self.name}")
        # 模拟提交失败
        if random.random() < 0.2:  # 20%的概率提交失败
            raise OperationException(message=f"提交事务 {self.name} 失败", code=7002)
        
        self.committed = True
    
    def rollback(self) -> None:
        """回滚事务"""
        if not self.started:
            raise OperationException(message="事务尚未开始，无法回滚", code=7003)
        
        if self.committed:
            raise OperationException(message="事务已提交，无法回滚", code=7004)
        
        logger.info(f"回滚事务: {self.name}")
        self.rolled_back = True
    
    def __enter__(self) -> 'Transaction':
        """上下文管理器入口"""
        self.start()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb) -> bool:
        """上下文管理器退出"""
        if exc_type is not None:
            # 发生异常，回滚事务
            try:
                self.rollback()
            except Exception as e:
                log_exception(e, log_level="ERROR", message=f"回滚事务 {self.name} 失败")
                return False  # 不抑制原始异常
        else:
            # 没有异常，提交事务
            try:
                self.commit()
            except Exception as e:
                # 提交失败，尝试回滚
                log_exception(e, log_level="ERROR", message=f"提交事务 {self.name} 失败")
                try:
                    self.rollback()
                except Exception as rollback_error:
                    log_exception(rollback_error, log_level="ERROR", message=f"回滚事务 {self.name} 失败")
                
                # 重新抛出提交异常
                raise
        
        return False  # 不抑制异常


def main():
    """主函数，运行所有示例"""
    logger.info("===== 异常处理模块高级用法示例 =====")
    
    # 示例1: 异常层次结构
    logger.info("\n----- 示例1: 异常层次结构 -----")
    # 获取所有注册的异常类型
    exceptions = exception_manager.get_all_registered_exceptions()
    logger.info(f"已注册的异常类型: {', '.join(exceptions.keys())}")
    
    # 示例2: 异常链和异常转换
    logger.info("\n----- 示例2: 异常链和异常转换 -----")
    try:
        data = fetch_api_data("https://api.example.com/data", auth_token="valid_token")
        logger.info(f"API返回数据: {data}")
    except APIException as e:
        logger.error(f"API异常: {e.message} (代码: {e.code})")
        if e.cause:
            logger.error(f"原始异常: {e.cause}")
    
    # 示例3: 异常过滤和分析
    logger.info("\n----- 示例3: 异常过滤和分析 -----")
    # 执行一些可能抛出异常的操作
    for _ in range(5):
        try:
            if random.random() < 0.3:
                raise ValidationException(message="验证失败", code=4001)
            elif random.random() < 0.3:
                raise TimeoutException(message="操作超时", code=4080)
            elif random.random() < 0.3:
                raise ValueError("无效的值")
        except Exception as e:
            exception_analyzer.collect(e)
    
    # 分析收集的异常
    logger.info(f"收集的异常数量: {exception_analyzer.get_exception_count()}")
    logger.info(f"异常类型统计: {exception_analyzer.get_exception_types()}")
    logger.info(f"最常见的异常类型: {exception_analyzer.get_most_common_exception()}")
    
    # 示例4: 与其他模块集成 - 数据库操作
    logger.info("\n----- 示例4: 与其他模块集成 - 数据库操作 -----")
    db = MockDatabase()
    try:
        # 连接数据库
        db.connect()
        
        # 查询数据
        results = db.query("users", {"age": {"$gt": 18}})
        logger.info(f"查询结果: {results}")
        
        # 插入数据
        record_id = db.insert("users", {"name": "John", "age": 30})
        logger.info(f"插入的记录ID: {record_id}")
    except DatabaseException as e:
        logger.error(f"数据库操作失败: {e.message} (代码: {e.code})")
    finally:
        # 断开数据库连接
        if db.connected:
            db.disconnect()
    
    # 示例5: 资源管理与异常处理
    logger.info("\n----- 示例5: 资源管理与异常处理 -----")
    resource_manager = ResourceManager()
    resource_manager.add_resource(Resource("Database Connection"))
    resource_manager.add_resource(Resource("File Handle"))
    resource_manager.add_resource(Resource("Network Socket"))
    
    try:
        with resource_manager:
            logger.info("使用资源执行操作...")
            # 模拟操作失败
            if random.random() < 0.5:  # 50%的概率操作失败
                raise OperationException(message="资源操作失败", code=7005)
    except OperationException as e:
        logger.error(f"操作异常: {e.message} (代码: {e.code})")
    
    # 示例6: 操作重试与回退策略
    logger.info("\n----- 示例6: 操作重试与回退策略 -----")
    
    # 自定义重试回调函数
    def custom_retry_callback(exc, attempt, delay):
        logger.warning(
            f"操作失败 (尝试 {attempt}/3): {str(exc)}. "
            f"将在 {delay:.2f} 秒后重试，使用自定义回退策略."
        )
    
    @with_backoff(max_attempts=3, initial_delay=0.5, backoff_factor=3.0,
                  exception_types=[TimeoutException, NetworkException],
                  on_retry=custom_retry_callback)
    def perform_network_operation():
        """执行网络操作，演示自定义重试策略"""
        logger.info("执行网络操作...")
        # 模拟操作失败
        if random.random() < 0.7:  # 70%的概率操作失败
            if random.random() < 0.5:
                raise TimeoutException(message="网络操作超时", code=4080)
            else:
                raise NetworkException(message="网络连接失败", code=4040)
        
        return {"status": "success", "data": "操作结果"}
    
    try:
        result = perform_network_operation()
        logger.info(f"网络操作结果: {result}")
    except (TimeoutException, NetworkException) as e:
        logger.error(f"网络操作最终失败: {e.message} (代码: {e.code})")
    
    # 示例7: 异常处理与事务管理
    logger.info("\n----- 示例7: 异常处理与事务管理 -----")
    try:
        with Transaction("UserRegistration"):
            logger.info("执行用户注册事务...")
            # 模拟事务操作
            if random.random() < 0.5:  # 50%的概率操作失败
                raise ValidationException(message="用户数据验证失败", code=4001)
            
            logger.info("用户注册成功")
    except Exception as e:
        if isinstance(e, BaseAppException):
            logger.error(f"事务失败: {e.message} (代码: {e.code})")
        else:
            logger.error(f"事务失败: {str(e)}")
    
    logger.info("\n===== 示例结束 =====")


if __name__ == "__main__":
    main()